﻿using FastExecutor.Base.Annotation;
using FastExecutor.Base.Design;
using FastExecutor.Base.Model;
using FastExecutor.Base.Util;
using FastExecutor.Message.Application;
using FastExecutor.ORG.Entity;
using FastExecutor.ORG.Enum;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Mvc;

namespace FastExecutor.ORG.Annotation
{
    public class SQLInjectionFillter : ActionFilterAttribute
    {
        public string[] SQLInjecttionChara = { "'", ";", " or ", "select", "update", "insert", "delete", "declare", "exec", "drop", "create", "%", "--" };

        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            bool IsSQLInject = false;
            StringBuilder ExceptionLog = new StringBuilder();
            ExceptionLog.AppendFormat(Environment.NewLine);
            Frame_ErrorLog LogEnity = new Frame_ErrorLog();
            LogEnity.RowGuid = CommonUtil.CreateCommonGuid();
            BaseController controller = (BaseController)filterContext.Controller;
            LogEnity.UGuid = controller.UserGuid;
            LogEnity.UName = controller.DisplayName;
            LogEnity.DGuid = controller.OUGuid;
            LogEnity.DName = controller.OUName;
            LogEnity.ErrorDate = DateTime.Now;
            LogEnity.FromIP = CommonUtil.GetClientIP();
            LogEnity.ErrorUrl = filterContext.HttpContext.Request.Url.ToString();
            LogEnity.ErrorType = (int)FrameEnum.ErrorType.SQLInjectionError;
            if (filterContext.ActionDescriptor.IsDefined(typeof(FastSQLInjectionAttribute), true) || filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(FastSQLInjectionAttribute), true))
            {
                #region url注入
                string[] url = filterContext.HttpContext.Request.Url.ToString().Split(new char[] { '?' }, StringSplitOptions.RemoveEmptyEntries);
                if (url.Length > 1)
                {
                    //url注入验证
                    string urlparam = url[1];
                    foreach (string item in SQLInjecttionChara)
                    {
                        if (urlparam.Contains(item))
                        {
                            IsSQLInject = true;
                            filterContext.Result = new RedirectResult(filterContext.RequestContext.HttpContext.Request.ApplicationPath + "/Frame/Error/ErrorSQLInjection/");//跳转至错误提示页面 
                            ExceptionLog.AppendFormat("异常请求url:{0}", filterContext.RequestContext.HttpContext.Request.Url + Environment.NewLine);
                            ExceptionLog.AppendFormat("异常信息Message:页面Url存在SQL注入风险，注入关键字为{0}", item + Environment.NewLine);
                            ExceptionLog.AppendFormat("========================================================================================================================================================================" + Environment.NewLine);
                            break;
                        }
                    }
                }
                #endregion

                #region 参数注入
                //参数注入验证
                JObject data = null;
                var req = filterContext.HttpContext.Request;
                var postBody = string.Empty;
                if (req.HttpMethod == "POST")
                {
                    var inp = req.InputStream;
                    var sr = new StreamReader(inp);
                    postBody = sr.ReadToEnd();
                    //重置stream，且不要调用dispose,否则controller获取参数的时候获取不到
                    inp.Seek(0, SeekOrigin.Begin);
                    data = (JObject)JsonConvert.DeserializeObject(postBody);
                }
                if (null != data)
                {
                    foreach (var item in data)
                    {
                        foreach (string sqlchara in SQLInjecttionChara)
                        {
                            if (item.Value.ToString().Contains(sqlchara))
                            {
                                IsSQLInject = true;
                                ReturnValue result = new ReturnValue();
                                result.Add("code", -998);
                                result.Add("msg", "参数存在SQL注入风险！");
                                filterContext.Result = result;
                                ExceptionLog.AppendFormat("异常请求url:{0}", filterContext.RequestContext.HttpContext.Request.Url + Environment.NewLine);
                                ExceptionLog.AppendFormat("异常信息Message:Ajax的请求参数存在SQL注入风险，注入参数名称为{0}，参数值为{1}，注入关键字为{2}", item.Key, item.Value,sqlchara + Environment.NewLine);
                                ExceptionLog.AppendFormat("========================================================================================================================================================================" + Environment.NewLine);
                                break;
                            }
                        }
                    }
                }
                #endregion

            }

            if (!IsSQLInject)
            {
                base.OnActionExecuting(filterContext);
            }
            else
            {
                LogEnity.ErrorContent = ExceptionLog.ToString();
                Dictionary<string, string> ExtraData = new Dictionary<string, string>();
                ExtraData.Add("LogFolder", "SQlInjectErrorLog");
                MessageCenter.GetInstance().SendMessage(FrameEnum.LogType.Error.ToString(), LogEnity, ExtraData);
            }
        }
    }
}
